﻿using System.Net;
using System.IO;
using HtmlAgilityPack;
using System.Text;
using System;
using System.ComponentModel;
using System.Reflection;
using System.Globalization;

namespace StockpriceFetcher
{
    /// <remarks>
    /// reference : http://msdn.microsoft.com/zh-tw/ee787055
    /// </remarks>
    class Stock
    {
        public Stock(int stockId)
        {
            Load(stockId);
        }

        private string GetDescriptionAttribute(PropertyInfo pi)
        {
            object[] attribs = pi.GetCustomAttributes(false);

            if (attribs.Length > 0)
            {
                var attrib = attribs[0] as DescriptionAttribute;

                if (attrib != null)
                    return attrib.Description;
            }
            return string.Empty;
        }

        public override string ToString()
        {
            StringBuilder output = new StringBuilder();

            Type t = GetType();
            foreach (PropertyInfo pi in t.GetProperties())
            {
                string name = GetDescriptionAttribute(pi);

                object value = pi.GetValue(this, null);

                output.AppendFormat("{0}: {1}\n", name, value);
            }

            return output.ToString();
        }

        private void Load(int stockId)
        {
            StockID = stockId;

            string address = string.Format("http://tw.stock.yahoo.com/q/q?s={0}", StockID);

            // 下載 Yahoo 奇摩股市資料 (範例為 2317 鴻海)
            WebClient client = new WebClient();
            MemoryStream ms = new MemoryStream(client.DownloadData(address));

            // 使用預設編碼讀入 HTML
            HtmlDocument doc = new HtmlDocument();
            doc.Load(ms, Encoding.Default);

            // 裝載第一層查詢結果
            HtmlDocument docStockContext = new HtmlDocument();

            docStockContext.LoadHtml(doc.DocumentNode.SelectSingleNode(
            "/html[1]/body[1]/center[1]/table[2]/tr[1]/td[1]/table[1]").InnerHtml);

            // 取得個股標頭
            HtmlNodeCollection nodeHeaders =
                docStockContext.DocumentNode.SelectNodes("./tr[1]/th");
            // 取得個股數值
            string[] values = docStockContext.DocumentNode.SelectSingleNode(
                "./tr[2]").InnerText.Trim().Split('\n');
            
            for(int i=0; i<values.Length; i++)
            {
                string value = values[i].Trim();

                switch (i)
                {
                    case 0:
                        {
                            value = value.Replace(StockID.ToString(), "");
                            value = value.Replace("加到投資組合", "");

                            Description = value;
                        } break;
                    case 1:
                        {
                            DateTime output;

                            string format = "HH:mm";

                            DateTime.TryParseExact(
                                value,
                                format,
                                CultureInfo.InvariantCulture,
                                DateTimeStyles.None,
                                out output);

                            Time = output;
                        } break;
                    case 2:
                        {
                            TransactionPrice = Convert.ToDouble(value);
                        } break;
                    case 3:
                        {
                            BuyingPrice = Convert.ToDouble(value);
                        } break;
                    case 4:
                        {
                            SellingPrice = Convert.ToDouble(value);
                        } break;

                    case 5:
                        {
                            double multiplier = value.Contains("▽") ? -1 : 1;

                            value = value.Replace("▽", "");
                            value = value.Replace("△", "");

                            PriceVariation = Convert.ToDouble(value);

                            PriceVariation = PriceVariation * multiplier;
                        } break;
                    case 6:
                        {
                            value = value.Replace(",", "");

                            NumberOfStock = Convert.ToInt32(value);
                        } break;
                    case 7:
                        {
                            ClosingPrice = Convert.ToDouble(value);
                        } break;
                    case 8:
                        {
                            OpeningPrice = Convert.ToDouble(value);
                        } break;
                    case 9:
                        {
                            HighestPrice = Convert.ToDouble(value);
                        } break;

                    case 10:
                        {
                            LowestPrice = Convert.ToDouble(value);
                        } break;
                    case 11:
                        {
                            // 個股資料
                        } break;
                }
            }
            
            doc = null;
            docStockContext = null;
            client = null;
            ms.Close();
        }

        [Description("股票代號")]
        public int StockID { get; set; }

        [Description("股票說明")]
        public string Description { get; set; }
        [Description("時間")]
        public DateTime Time { get; set; }
        [Description("成交價")]
        public double TransactionPrice { get; set; }
        [Description("買進價")]
        public double BuyingPrice { get; set; }
        [Description("賣出價")]
        public double SellingPrice { get; set; }

        [Description("漲跌")]
        public double PriceVariation { get; set; }
        [Description("總張數")]
        public int NumberOfStock { get; set; }
        [Description("收盤價")]
        public double ClosingPrice { get; set; }
        [Description("開盤價")]
        public double OpeningPrice { get; set; }
        [Description("最高價")]
        public double HighestPrice { get; set; }

        [Description("最低價")]
        public double LowestPrice { get; set; }
    }

    class Program
    {
        public static void Main(string[] args)
        {
            Stock stock = null;

            int[] StockIDs = 
            {
                2221,
                2881,
                2886
            };

            foreach (int StockID in StockIDs)
            {
                stock = new Stock(StockID);
                Console.WriteLine(stock.ToString());
            }

            Console.ReadLine();
        }
    }
}
